/**
 * 
 */
package wayic.http;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import wayic.commons.WayicResourceEx;

/**
 * Factory for getting 
 * - new UrLoader objects, 
 * - singleton HttpClient object to be used by HttFetcher.
 *  
 * @author Ashesh Nishant
 *
 */
public class HttpFactory {
	
	private final static Logger LOGGER = LogManager.getLogger(HttpFactory.class);
	
	private final static HttpLoader defaultClient = new AbstractHttpLoader(){
		public String getUserAgent(){
			return WAYIC_USER_AGENT;
		}
	};
	
	private final static HttpLoader ieClient = new AbstractHttpLoader(){
		public String getUserAgent(){
			return IE_USER_AGENT;
		}
	};
	
	private final static HttpLoader firefoxClient = new AbstractHttpLoader(){
		public String getUserAgent(){
			return FIREFOX_USER_AGENT;
		}
	};
	
	private final static HttpLoader googlebotClient = new AbstractHttpLoader(){
		public String getUserAgent(){
			return GOOGLEBOT_USER_AGENT;
		}
	};
	
	public static final String WAYIC_USER_AGENT = "WayIc HttpUrlLoader V1.0";
	public static final String IE_USER_AGENT = "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 6.0)";
	public static final String FIREFOX_USER_AGENT = "	Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.9) Gecko/20061206 Firefox/1.5.0.9";
	public static final String GOOGLEBOT_USER_AGENT ="Googlebot/2.1 (+http://www.googlebot.com/bot.html)"; 
	
	/**
	 * Returns a URLLoader with the following features:
	 * Conditional-GET fetch(based on last-modified and etag), 
	 * User-agent, Connection-timeout, Redirect-enabled.
	 *   
	 * @param url. From where to fetch the input.
	 * @return
	 */
	public static UrlLoader urlLoader(URL url){
		// TODO read these properties from a config
		//User-Agent:WAYIC_USER_AGENT; Redirect-enabled:true; Connection-timeout: 5000 ms
		UrlFetcher loader = new UrlFetcher(WAYIC_USER_AGENT, true, 5000, url);
		return loader;
	}
	
	/**
	 * Delegate for 
	 * @see wayic.http.HttpFactory.utils.LoaderFactory#urlLoader(java.net.URL)
	 * 
	 * @param urlStr. From where to fetch the input.
	 * @return
	 * @throws MalformedURLException. If urlStr cannot be resolved to a URL.
	 */
	public static UrlLoader urlLoader(String urlStr) throws WayicResourceEx{
		URL url = null;
		try{
			url = new URL(urlStr);
		}catch(MalformedURLException mux){
			LOGGER.warn("Cannot fetch from "+urlStr);
			throw new WayicResourceEx("Cannot fetch from "+urlStr, mux);
		}
		return HttpFactory.urlLoader(url);
	}
	
	/**
	 * Returns a URLLoader created with Apache HttpClient with the following features:
	 * Following features have been customized:
	 * -RETRY_HANDLER
	 * -USER_AGENT
	 * -ALLOW_CIRCULAR_REDIRECTS
	 * -REJECT_RELATIVE_REDIRECT
	 * -MAX_REDIRECTS
	 * -Multi threaded Connection Manager
	 * -MaxTotalConnections
	 * -ConnectionTimeout
	 * -KEEP-ALIVE connection
	 * -TcpNoDelay.
	 *   
	 * @param url. From where to fetch the input.
	 * @return
	 * @throws WayicResourceEx 
	 */
	public static UrlLoader httpLoader(URL url) throws WayicResourceEx {
	    HttpFetcher loader = null;
	    loader = new HttpFetcher(getDefaultHttpClient(), url);
	    return loader;
	}
	
	public static UrlLoader httpLoaderForIE(URL url) throws WayicResourceEx {
	    HttpFetcher loader = null;
	    loader = new HttpFetcher(getIeHttpClient(), url);
	    return loader;
	}
	
	public static UrlLoader httpLoaderForGoogle(URL url) throws WayicResourceEx {
	    HttpFetcher loader = null;
	    loader = new HttpFetcher(getGooglebotHttpClient(), url);
	    return loader;
	}
	
	public static UrlLoader httpLoaderForFireFox(URL url) throws WayicResourceEx {
	    HttpFetcher loader = null;
	    loader = new HttpFetcher(getFirefoxHttpClient(), url);
	    return loader;
	}
	
	/**
	 * Delegate for 
	 * @see wayic.http.HttpFactory.utils.LoaderFactory#httpLoader(java.net.URL)
	 * 
	 * @param urlStr. From where to fetch the input.
	 * @return
	 * @throws MalformedURLException. If urlStr cannot be resolved to a URL.
	 */
	public static UrlLoader httpLoader(String urlStr) throws WayicResourceEx{
		URL url = null;
		try{
			url = new URL(urlStr);
		}catch(MalformedURLException mux){
			LOGGER.warn("Cannot fetch from "+urlStr);
			throw new WayicResourceEx("Cannot fetch from "+urlStr, mux);
		}
		return HttpFactory.httpLoader(url);
	}
	
	
	/**
	 * Returns a customized variety of Apache HttpClient as a singleton object. 
	 * See API doc of AbstractHttpClient to understand the customizations.
	 * This client should not be used for loading form non-Http URLs.
	 * This client has the User-Agent string as "WayIc Feed-Loader V0.1a."
	 * 
	 * @return
	 */
	public static HttpLoader getDefaultHttpClient(){
		return defaultClient;
	}
	
	/**
	 * Returns a customized variety of Apache HttpClient as a singleton object.
	 * This client mimics Internet Explorer browser. 
	 * See API doc of AbstractHttpClient to understand the customizations.
	 * This client should not be used for loading from non-Http URLs.
	 * 
	 * @return
	 */
	public static HttpLoader getIeHttpClient(){
		return ieClient;
	}
	
	/**
	 * Returns a customized variety of Apache HttpClient as a singleton object.
	 * This client mimics Firefox browser. 
	 * See API doc of AbstractHttpClient to understand the customizations.
	 * This client should not be used for loading from non-Http URLs.
	 * 
	 * @return
	 */
	public static HttpLoader getFirefoxHttpClient(){
		return firefoxClient;
	}
	
	/**
	 * ********************************************************
	 * THE USAGE IN PRODUCTION IS STRICTLY DISCOURAGED - 
	 * it amounts to cloaking and 
	 * is in most cases against the terms of services of Google.
	 * *********************************************************
	 * Returns a customized variety of Apache HttpClient as a singleton object.
	 * This client mimics Googlebot. 
	 * See API doc of AbstractHttpClient to understand the customizations.
	 * This client should not be used for loading from non-Http URLs.
	 * 
	 * @return
	 */
	public static HttpLoader getGooglebotHttpClient(){
		LOGGER.warn("THE USAGE IS STRICTLY DISCOURAGED - it amounts to cloaking and is in most cases against the terms of services of Google");
		return googlebotClient;
	}
	
	/**
	 * This method should be called only for cleanup on System exit. 
	 * Note that there is no restart available for a client which has been shutdown.
	 * 
	 * @param client
	 */
	public static void shutDown(HttpLoader client){
		if(client instanceof AbstractHttpLoader){
			AbstractHttpLoader cl = (AbstractHttpLoader)client;
			cl.shutdown();
		}
	}
	
	/**
	 * This method uses the implementation of URLFetcher 
	 * returned by httpLoader() to load content
	 *  
	 * @param url
	 * @return
	 */
	public static Content load(URL url){
	    try {
            UrlLoader loader = httpLoader(url);
            try {
                ContentHeader header = loader.load();
                String contentStr = loader.getAsString();
                Content content = new Content();
                content.setContent(contentStr);
                content.setContentHeader(header);
                return content;
            } catch (IOException e) {
                e.printStackTrace();
                LOGGER.error("Could not create HTTP LOader for " + url + " due to " + e.getMessage());
            } finally{
                if(loader != null){
                    loader.close();
                }
            }
        } catch (WayicResourceEx e) {
            e.printStackTrace();
            LOGGER.error("Could not create HTTP LOader for " + url + " due to " + e.getMessage());
        } 
        return null;
	}
}
